package repository

import (
	"context"
	"errors"

	"gorm.io/gorm"

	"BookStack/internal/domain/tag"
)

// tagRepository 标签仓储实现
type tagRepository struct {
	db *gorm.DB
}

// NewTagRepository 创建标签仓储
func NewTagRepository(db *gorm.DB) tag.Repository {
	return &tagRepository{
		db: db,
	}
}

// Create 创建标签
func (r *tagRepository) Create(ctx context.Context, t *tag.Tag) error {
	return r.db.WithContext(ctx).Create(t).Error
}

// Update 更新标签
func (r *tagRepository) Update(ctx context.Context, t *tag.Tag) error {
	return r.db.WithContext(ctx).Save(t).Error
}

// Delete 删除标签
func (r *tagRepository) Delete(ctx context.Context, id uint) error {
	return r.db.WithContext(ctx).Delete(&tag.Tag{}, id).Error
}

// BatchDelete 批量删除标签
func (r *tagRepository) BatchDelete(ctx context.Context, ids []uint) error {
	return r.db.WithContext(ctx).Delete(&tag.Tag{}, ids).Error
}

// GetByID 根据ID获取标签
func (r *tagRepository) GetByID(ctx context.Context, id uint) (*tag.Tag, error) {
	var t tag.Tag
	if err := r.db.WithContext(ctx).First(&t, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return &t, nil
}

// GetBySlug 根据Slug获取标签
func (r *tagRepository) GetBySlug(ctx context.Context, slug string) (*tag.Tag, error) {
	var t tag.Tag
	if err := r.db.WithContext(ctx).Where("slug = ?", slug).First(&t).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return &t, nil
}

// GetByName 根据Name获取标签
func (r *tagRepository) GetByName(ctx context.Context, name string) (*tag.Tag, error) {
	var t tag.Tag
	if err := r.db.WithContext(ctx).Where("name = ?", name).First(&t).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return &t, nil
}

// ExistsByName 检查名称是否存在
func (r *tagRepository) ExistsByName(ctx context.Context, name string, tagType int, excludeID uint) (bool, error) {
	var count int64
	query := r.db.WithContext(ctx).Model(&tag.Tag{}).Where("name = ? AND type = ?", name, tagType)
	if excludeID > 0 {
		query = query.Where("id != ?", excludeID)
	}
	if err := query.Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}

// ExistsBySlug 检查Slug是否存在
func (r *tagRepository) ExistsBySlug(ctx context.Context, slug string, tagType int, excludeID uint) (bool, error) {
	var count int64
	query := r.db.WithContext(ctx).Model(&tag.Tag{}).Where("slug = ? AND type = ?", slug, tagType)
	if excludeID > 0 {
		query = query.Where("id != ?", excludeID)
	}
	if err := query.Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}

// List 获取标签列表
func (r *tagRepository) List(ctx context.Context, params *tag.ListParams) ([]*tag.Tag, int64, error) {
	var tags []*tag.Tag
	var total int64

	query := r.db.WithContext(ctx).Model(&tag.Tag{})

	// 应用类型筛选
	if params.Type != nil {
		query = query.Where("type = ?", *params.Type)
	}

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (params.Page - 1) * params.Size
	if err := query.Order("created_at DESC").
		Offset(offset).
		Limit(params.Size).
		Find(&tags).Error; err != nil {
		return nil, 0, err
	}

	return tags, total, nil
}

// GetHotTags 获取热门标签
func (r *tagRepository) GetHotTags(ctx context.Context, tagType *int, limit int) ([]*tag.Tag, error) {
	var tags []*tag.Tag
	query := r.db.WithContext(ctx).Model(&tag.Tag{})

	// 应用类型筛选
	if tagType != nil {
		query = query.Where("type = ?", *tagType)
	}

	if err := query.Order("usage_count DESC").
		Limit(limit).
		Find(&tags).Error; err != nil {
		return nil, err
	}

	return tags, nil
}

// GetTagStat 获取标签使用统计
func (r *tagRepository) GetTagStat(ctx context.Context, id uint) (articleCount int64, bookCount int64, err error) {
	// 获取文章标签关联数量
	if err := r.db.WithContext(ctx).
		Model(&struct{}{}).
		Table("article_tags").
		Where("tag_id = ?", id).
		Count(&articleCount).Error; err != nil {
		return 0, 0, err
	}

	// 获取书籍标签关联数量
	if err := r.db.WithContext(ctx).
		Model(&struct{}{}).
		Table("book_tags").
		Where("tag_id = ?", id).
		Count(&bookCount).Error; err != nil {
		return 0, 0, err
	}

	return articleCount, bookCount, nil
}

// UpdateUsageCount 更新标签使用计数
func (r *tagRepository) UpdateUsageCount(ctx context.Context, id uint, count int64) error {
	return r.db.WithContext(ctx).
		Model(&tag.Tag{}).
		Where("id = ?", id).
		Update("usage_count", count).Error
}
